package jat.xtext.gantt.ui.diagram;

import jat.xtext.gantt.ganttText.Person;
import jat.xtext.gantt.ganttText.Role;
import jat.xtext.gantt.ganttText.RoleAssignment;
import jat.xtext.gantt.ganttText.Task;
import jat.xtext.gantt.ganttText.Time;
import jat.xtext.gantt.ganttText.WorkPackage;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;

public class GanttChartHelpers {

	/**
	 * TODO The current implementation only returns a rough value (i.e. weekends
	 * are included)
	 * 
	 * @param time
	 * @return
	 */
	public static int getNumWorkingDays(Time time) {
		if (time == null) {
			return 0;
		}

		int timeSpent = 0;
		timeSpent += time.getYears() * 240;
		timeSpent += time.getMonths() * 20;
		timeSpent += time.getWeeks() * 5;
		timeSpent += time.getDays();
		return timeSpent;
	}

	/**
	 * @param task
	 *            Something that can be put off until a more convenient time.
	 * @return The required time (in days) to complete a task.
	 */
	public static int getRequiredTime(Task task) {
		int taskEffort = 0;
		float requiredTime = 0;

		if (task.getTaskDuration() != null) {
			taskEffort = GanttChartHelpers.getNumWorkingDays(task.getTaskDuration().getEffort());
			requiredTime = taskEffort;

			HashMap<Role, ArrayList<Person>> assignmentLookup = new HashMap<Role, ArrayList<Person>>();
			if (task.getTaskDuration().getRoleAssignments() != null) {
				for (RoleAssignment roleAssignment : task.getTaskDuration().getRoleAssignments()) {
					if (assignmentLookup.get(roleAssignment.getRole()) == null) {
						assignmentLookup.put(roleAssignment.getRole(), new ArrayList<Person>());
					}
					assignmentLookup.get(roleAssignment.getRole()).addAll(roleAssignment.getPersons());
				}
			}

			if (task.getTaskDuration().getTaskType() != null) {
				for (Role role : task.getTaskDuration().getTaskType().getRoles()) {
					if (assignmentLookup.get(role) != null) {
						requiredTime += ((role.getTaskWeight() / 100.0) * taskEffort)
								/ assignmentLookup.get(role).size();
					} else {
						requiredTime += (role.getTaskWeight() / 100.0) * taskEffort;
					}
				}
			}
		}

		return (int) requiredTime;
	}

	/**
	 * @param startDate
	 * @param task
	 *            Something that can be put off until a more convenient time.
	 * @return The required time (in days) to complete a task.
	 */
	public static Calendar getEndDate(Calendar startDate, Task task) {
		Calendar currentDate = (Calendar) startDate.clone();
		final int requiredTime = getRequiredTime(task);

		for (int daysWorked = 0; daysWorked < requiredTime;) {
			final int dayOfWeek = currentDate.get(Calendar.DAY_OF_WEEK);
			if (dayOfWeek != Calendar.SATURDAY && dayOfWeek != Calendar.SUNDAY) {
				daysWorked++;
			}
			if (daysWorked < requiredTime) {
				currentDate.add(Calendar.DATE, 1);
			}
		}

		return currentDate;
	}

	/**
	 * @return The total required time for each task within the package.
	 */
	public static int getRequiredTime(WorkPackage pack) {
		int requiredTime = 0;
		for (Task task : pack.getTasks()) {
			requiredTime = GanttChartHelpers.getRequiredTime(task);
		}
		return requiredTime;
	}

	/**
	 * @return The percent complete of a task in the range: 0..100.
	 */
	public static int getPercentComplete(Task task) {
		double timeSpent = GanttChartHelpers.getNumWorkingDays(task.getTaskDuration().getCompletion());
		double totalEffort = GanttChartHelpers.getNumWorkingDays(task.getTaskDuration().getEffort());
		if (totalEffort == 0) {
			return 0;
		} else {
			return (int) ((timeSpent / totalEffort) * 100);
		}
	}
}
